﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;

namespace EtcpSharp
{
    /// <summary>
    /// ETCP服务
    /// </summary>
    internal class ETcpServe : IETCPSocketService
    {
        static ETcpServe()
        {
        }

        #region 字段

        public delegate void tcp_fun(IntPtr Server, IntPtr so, int type, IntPtr buf, int len, int count);

        public delegate void tcp_fun_client(IntPtr Client, IntPtr so, int type, IntPtr buf, int len);

        tcp_fun _tcp_Fun = null;
        tcp_fun_client _tcp_fun_client = null;

        //服务器指针
        IntPtr _serverIntPtr;

        /// <summary>
        /// 客户端
        /// </summary>
        List<IClientSocketSessionServer> _clientSocketSessionServers = new List<IClientSocketSessionServer>();

        Dictionary<string, IntPtr> _clientSocketSessionDiv = new Dictionary<string, IntPtr>();
        Dictionary<IntPtr, string> _clientSocketSessionIDDiv = new Dictionary<IntPtr, string>();

        //同步
        private object syncobj = new object();

        public event EventHandler<ETCPClientDataReceivedEventArgs> Received;

        public event EventHandler<ETCPClientConnectedEventArgs> Connected;

        public event EventHandler<ETCPClientDisconnectedEventArgs> Disconnected;

        #endregion 字段

        #region dll调用

        /// <summary>
        /// 初始化
        /// </summary>
        /// <param name="nFun"></param>
        /// <param name="cFun"></param>
        /// <param name="buflen"></param>
        /// <returns></returns>
        [DllImport("etcp60.dll", CallingConvention = CallingConvention.StdCall, EntryPoint = "#14")]
        static extern int etcp_vip_number(tcp_fun nFun, tcp_fun_client cFun, int buflen);

        /// <summary>
        /// 打开服务
        /// </summary>
        /// <param name="host"></param>
        /// <param name="port"></param>
        /// <param name="nIs"></param>
        /// <returns></returns>
        [DllImport("etcp60.dll", CallingConvention = CallingConvention.StdCall)]
        static extern IntPtr etcp_tcp_server(StringBuilder host, int port, int nIs);

        /// <summary>
        /// 发送数据
        /// </summary>
        /// <param name="sso"></param>
        /// <param name="so"></param>
        /// <param name="buf"></param>
        /// <param name="len"></param>
        /// <returns></returns>
        [DllImport("etcp60.dll", CallingConvention = CallingConvention.StdCall)]
        static extern int etcp_tcp_send(IntPtr sso, IntPtr so, StringBuilder buf, int len);

        /// <summary>
        /// 关闭服务器
        /// </summary>
        /// <param name="server"></param>
        /// <returns></returns>
        [DllImport("etcp60.dll", CallingConvention = CallingConvention.StdCall)]
        static extern int etcp_tcp_close(IntPtr server);

        /// <summary>
        /// 是否关闭客户端
        /// </summary>
        /// <param name="client"></param>
        /// <returns></returns>
        [DllImport("etcp60.dll", CallingConvention = CallingConvention.StdCall)]
        static extern int etcp_tcp_close_Client(IntPtr client);

        /// <summary>
        /// 获取服务器端口
        /// </summary>
        /// <param name="server"></param>
        /// <returns></returns>
        [DllImport("etcp60.dll", CallingConvention = CallingConvention.StdCall)]
        static extern int etcp_tcp_get_port(IntPtr server);

        #endregion dll调用

        /// <summary>
        /// 地址
        /// </summary>
        public string Host { get; set; } = "127.0.0.1";

        /// <summary>
        /// 端口
        /// </summary>
        public ushort Port { get; set; }

        /// <summary>
        /// 日志输出
        /// </summary>
        public Action<string> Log { get; set; }

        /// <summary>
        /// 初始化
        /// </summary>
        public string Initialize()
        {
            _tcp_Fun = ReceiveServe;
            _tcp_fun_client = ReceiveClient;
            var resInit = etcp_vip_number(_tcp_Fun, _tcp_fun_client, 8192);
            if (resInit <= 0)
            {
                return "初始化失败";
            }
            return "";
        }

        /// <summary>
        /// 启动服务
        /// </summary>
        public void Start()
        {
            _serverIntPtr = etcp_tcp_server(new StringBuilder(this.Host), this.Port, 1);
            if (this.Port <= 0)
            {
                this.Port = (ushort)etcp_tcp_get_port(_serverIntPtr);
            }
        }

        /// <summary>
        /// 收到消息
        /// </summary>
        /// <param name="server">便于分辨服务端，"服务端创建"返回的句柄。</param>
        /// <param name="client">便于分辨客户端，客户端的socket。</param>
        /// <param name="type">1、客户进入 2、数据到达 3、客户断开，#etcp_ 常量。</param>
        /// <param name="buf">数据地址</param>
        /// <param name="len">长度</param>
        /// <param name="count">客户端数量</param>
        private void ReceiveServe(IntPtr server, IntPtr client, int type, IntPtr buf, int len, int count)
        {
            switch (type)
            {
                case 1:
                    IClientSocketSessionServer clientSer = null;
                    //有客户端连接
                    lock (syncobj)
                    {
                        string id = MD5Helper.MD5Encrypt01(client.ToString());
                        clientSer = new ClientSocketSessionServer(this, client, id);
                        _clientSocketSessionServers.Add(clientSer);
                        _clientSocketSessionDiv[id] = client;
                        _clientSocketSessionIDDiv[client] = id;
                    }
                    this.Connected?.Invoke(this, new ETCPClientConnectedEventArgs()
                    {
                        Client = clientSer,
                        Serve = this
                    });
                    break;

                case 2:
                    //数据到达.
                    var message = Marshal.PtrToStringAnsi(buf, len);
                    var clientid = _clientSocketSessionIDDiv[client];
                    this.Received?.Invoke(this, new ETCPClientDataReceivedEventArgs()
                    {
                        Client = _clientSocketSessionServers.FirstOrDefault(w => w.Id == clientid),
                        Length = len,
                        Message = message,
                        Serve = this
                    });
                    break;

                case 3:
                    //客户断开.
                    var clientid1 = _clientSocketSessionIDDiv[client];
                    lock (syncobj)
                    {
                        _clientSocketSessionServers.RemoveAll(w => w.Id == clientid1);
                        if (_clientSocketSessionDiv.ContainsKey(clientid1))
                        {
                            _clientSocketSessionDiv.Remove(clientid1);
                        }
                        if (_clientSocketSessionIDDiv.ContainsKey(client))
                        {
                            _clientSocketSessionIDDiv.Remove(client);
                        }
                    }
                    this.Disconnected?.Invoke(this, new ETCPClientDisconnectedEventArgs()
                    {
                        Serve = this,
                        ClientId = clientid1
                    });

                    break;

                default:

                    break;
            }
        }

        /// <summary>
        /// 收到客户端信息
        /// </summary>
        /// <param name="client"></param>
        /// <param name="so"></param>
        /// <param name="type"></param>
        /// <param name="buf"></param>
        /// <param name="len"></param>
        private void ReceiveClient(IntPtr client, IntPtr so, int type, IntPtr buf, int len)
        {
        }

        /// <summary>
        /// 资源释放
        /// </summary>
        public void Dispose()
        {
            try
            {
                Colse();
            }
            catch
            {
            }
        }

        /// <summary>
        /// 关闭服务器
        /// </summary>
        public void Colse()
        {
            try
            {
                if (this._serverIntPtr == null)
                {
                    return;
                }
                etcp_tcp_close(_serverIntPtr);
            }
            catch
            {
            }
        }

        /// <summary>
        /// 日志初始化
        /// </summary>
        /// <param name="text"></param>
        public void ShowLog(string text)
        {
            this.Log?.Invoke(text);
        }

        /// <summary>
        /// 获取客户端
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public IClientSocketSessionServer GetClient(string id)
        {
            return this._clientSocketSessionServers.Where(w => w.Id == id).FirstOrDefault();
        }

        /// <summary>
        /// 发送数据
        /// </summary>
        /// <param name="client"></param>
        /// <param name="sb"></param>
        public void Send(IClientSocketSessionServer client, StringBuilder sb)
        {
            if (!_clientSocketSessionDiv.ContainsKey(client.Id))
            {
                return;
            }
            var ipr = _clientSocketSessionDiv[client.Id];
            etcp_tcp_send(this._serverIntPtr, ipr, sb, sb.Length);//发送消息
        }

        /// <summary>
        /// 关闭客户端
        /// </summary>
        /// <param name="id"></param>
        public void ColseClient(string id)
        {
            if (!_clientSocketSessionDiv.ContainsKey(id))
            {
                return;
            }
            var ipr = _clientSocketSessionDiv[id];
            etcp_tcp_close_Client(ipr);//断开
            lock (syncobj)
            {
                _clientSocketSessionServers.RemoveAll(w => w.Id == id);
                _clientSocketSessionDiv.Remove(id);
            }
        }

        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name="clientid"></param>
        /// <param name="sb"></param>
        public void Send(string clientid, StringBuilder sb)
        {
            if (!_clientSocketSessionDiv.ContainsKey(clientid))
            {
                return;
            }
            var ipr = _clientSocketSessionDiv[clientid];
            etcp_tcp_send(this._serverIntPtr, ipr, sb, sb.Length);//发送消息
        }
    }
}